﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Play
{
    public class NimState
    {
        public readonly int[] Heaps;
        public readonly NimState Parent;
        public readonly PlayerType PlayerType;
        public readonly NimMove Move;
        public readonly List<NimState> Children;
        public int MiniMax;
        public int Alpha;
        public int Beta;
        public bool Pruned;

        public NimState(int[] heaps, NimState parent, PlayerType playerType, NimMove move)
        {
            Heaps = heaps;
            Parent = parent;
            PlayerType = playerType;
            Move = move;
            Children = new List<NimState>();
            Alpha = int.MinValue;
            Beta = int.MaxValue;
            Pruned = false;
        }

        public void RemovePieces(NimMove move)
        {
            //move valid check
            if (move.HeapIndex >= Heaps.Length) 
                throw new Exception(string.Format("HeapIndex={0} does not exists", move.HeapIndex));

            if (move.Pieces > Heaps[move.HeapIndex]) 
                throw new Exception(string.Format("Move Pieces={0} is bigger then heap size", move.Pieces));

            Heaps[move.HeapIndex] -= move.Pieces;
        }

        public bool HasPieces()
        {
            int pieces = Heaps.Sum();
            return pieces > 0;
        }

        public override string ToString()
        {
            var moveStr = (Move == null) ? string.Empty : Move.ToString();
            return moveStr + "State=[player:" + PlayerType + ",heaps={" + string.Join(",", Heaps) + "}]";
        }

        public void UpdateAlphaBeta(int minimax)
        {
            //improve alpha/beta if possible
            if (PlayerType == PlayerType.Max)
                Alpha = Math.Max(Alpha, minimax);
            else
                Beta = Math.Min(Beta, minimax);
        }

        public bool IsPruneNeeded()
        {
            return (Alpha >= Beta);
        }

        public void UpdateMinimax(int miniMax)
        {
            //set minimax for the first time
            if (MiniMax == 0)
            {
                MiniMax = miniMax;
                return;
            }

            //improve mimimax if possible
            MiniMax = (PlayerType == PlayerType.Max)
                ? Math.Max(MiniMax, miniMax)
                : Math.Min(MiniMax, miniMax);
        }
    }
}